﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using BenchmarkApp.Utils;
using System.Diagnostics;
using THO7_Team8;

namespace BenchmarkApp
{
    public partial class MainForm : Form
    {
        private String workingDirectory = "";
        private XMLProvider imageXmlInput;
        private XMLProvider testResultXml;
        List<Double> ocrAccuracy = new List<Double>();
        List<long> executionTime = new List<long>();
        int perfectImages;
        private List<TestsetImage> imagesToProcess = new List<TestsetImage>();

        public MainForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Opens an existing XML file that describes a test set.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openXmlAndLoadImages(object sender, EventArgs e)
        {
            if (openXMLDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                imageXmlInput = new XMLProvider(new FileInfo(openXMLDialog1.FileName));
                FileInfo fi = new FileInfo(openXMLDialog1.FileName);
                workingDirectory = fi.Directory.ToString();
                if (imageXmlInput.rootNode.Name == "testsamples")
                {
                    foreach (XmlNode imgNode in imageXmlInput.rootNode.ChildNodes)
                    {
                        listBox1.Items.Add(imgNode.Attributes["filename"].Value + "Loaded.");
                        List<String> licensePlates = new List<String>();
                        foreach(XmlNode potentialLicensePlateNode in imgNode.ChildNodes)
                            if(potentialLicensePlateNode.Name == "license_plate"){
                                foreach(XmlNode potentialTextNode in potentialLicensePlateNode.ChildNodes)
                                    if(potentialTextNode.Name == "text"){
                                        licensePlates.Add(potentialTextNode.InnerText);
                                    }
                            };
                        String[] originalLicensePlates = licensePlates.ToArray();
                        imagesToProcess.Add(new TestsetImage(new Bitmap(workingDirectory + "\\" + imgNode.Attributes["filename"].Value), imgNode.Attributes["filename"].Value, licensePlates.ToArray()));
                        textBox1.Text = "" + imagesToProcess.Count;
                    }
                }
                runButton.Enabled = true;
            }
        }

        /// <summary>
        /// Handles the click-event on the Run-button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void runButton_click(object sender, EventArgs e)
        {
            createResultXml("test");
            perfectImages = 0;
            imageOperationWorker.RunWorkerAsync();
        }


        /// <summary>
        /// Instantiates testResultXml with the provided filename.
        /// </summary>
        /// <param name="filename">The filename to save the Xml to</param>
        private void createResultXml(String filename)
        {
            FileInfo f = new FileInfo(workingDirectory + "\\results " + DateTime.Now.ToString("d-M-yyyy HH.mm.ss") + ".xml");
            testResultXml = new XMLProvider(f, "testresults");
        }

        /// <summary>
        /// Runs all the operations related to numberplate detection and OCR on an image.
        /// </summary>
        /// <param name="tsi"></param>
        private void processImage(TestsetImage tsi)
        {
            List<NumberPlate> numberPlateList = new List<NumberPlate>();
            Stopwatch imageOperationTimer = new Stopwatch();
            tjerkocr2.TestOCRAlgorithm tjerkocr = new tjerkocr2.TestOCRAlgorithm("HOI");
            imageOperationTimer.Start();

            //Creates a return image, this is needed because otherwise the pixelFormat will be wrong 
            Bitmap returnImage = new Bitmap(tsi.SourceImage);
            //originalArray is used to return the original colors after crop
            int[] originalArray = MyImage.BmpToArray(returnImage);

            //imageArray is used in all the algoritms
            int[] imageArray = new int[originalArray.Length];
            originalArray.CopyTo(imageArray, 0);

            //SimpleColorDetect checks for yellowpixels in the image
            SimpleColorDetectMonogrome simpleColorDetectMonochrome = new SimpleColorDetectMonogrome();
            simpleColorDetectMonochrome.DoAlgorithm(ref imageArray);

            //BlobDetection to filter small blobs, multiple blobs and blobs which do not have the right dimensions
            LicensePlateBlobDetection licensePlateBlobDetection = new LicensePlateBlobDetection();
            licensePlateBlobDetection.DoAlgorithm(ref imageArray, tsi.SourceImage.Width);
            
            
            //numberPlateList.Add(new NumberPlate(new Point(1, 1), new Point(1, 1), new Point(1, 1), new Point(1, 1), "00-00-00"));
            Point[] coords = BlobUtils.getCoordinates(ref imageArray, tsi.SourceImage.Width);
            numberPlateList.Add(new NumberPlate(coords[0], coords[1], coords[2], coords[3]));

            //For each numberplate do lighting
            foreach (NumberPlate np in numberPlateList)
            {
                //Do lighting
                //Do transform
                //Do segmentation, store results in some kind of segmentsArray
                CropLicenseplateColoured cropLicensePlateColored = new CropLicenseplateColoured();
                Bitmap croppedBitmap = cropLicensePlateColored.DoAlgorithm(ref imageArray, ref originalArray, tsi.SourceImage.Width);
                int[] croppedArray;
                if (croppedBitmap != null)
                {
                    //croppedArray is the array to be used in the next algoritms
                    croppedArray = MyImage.BmpToArray(croppedBitmap);
                    //Make monochrome, needed for cropEdges
                    MakeMonochrome makeMonochrome = new MakeMonochrome();
                    makeMonochrome.DoAlgorithm(ref croppedArray);
                    Bitmap monochromeBitmap = new Bitmap(croppedBitmap);
                    monochromeBitmap = MyImage.ArrayToBmp(imageArray, monochromeBitmap);
                    //Rotate the license plate
                    //We do not use this at the moment, it makes the result often worse
                    //RotateLicensePlate rotateLicensePlate = new RotateLicensePlate("");
                    //Bitmap rotateLicensePlateResult = rotateLicensePlate.DoAlgorithm(monochromeBitmap);

                    //Crops the black edges around the license plate, also filters noise
                    CropEdges cropEdges = new CropEdges();
                    Bitmap[] characters = cropEdges.DoAlgorithm(ref croppedArray, croppedBitmap.Width, croppedBitmap.Height);
                    String theDetectedCharacters = "";
                    foreach (Bitmap ocrSegment in characters)
                    {
                        Random random = new Random();
                        ocrSegment.Save("quatsj_" + random.Next(0, 100) + ".jpg");
                        theDetectedCharacters += tjerkocr.DoOCRAndGetCandidate(ocrSegment);
                    }
                    np.DetectedCharacters = theDetectedCharacters;
                    //for each segment in segmentsArray: doOcr. Store the results in np.DetectedCharacters like this:
                    //tjerkocr.DoOCR(segment);   
                    //np.DetectedCharacters = detectedCharacters; 
                    double d = Results.measureOcrPrecision(tsi.originalCharacters, new String[1] { np.DetectedCharacters });
                    if (d == 100)
                    {
                        perfectImages++;
                    }
                    ocrAccuracy.Add(d); //TODO: Replace with actual data

                }
                else
                {
                    np.DetectedCharacters = "ERROR";
                }
               
            }

            imageOperationTimer.Stop();
            executionTime.Add(imageOperationTimer.ElapsedMilliseconds);
            
            //These lines create a new XML Element containing the information about the license plates detected in this picture.
            XmlNode newNode = Results.createResultXmlNode(tsi.fileName, numberPlateList.ToArray(), imageOperationTimer.ElapsedMilliseconds, testResultXml);
            testResultXml.activeNode.AppendChild(newNode);
        }




        private void processAllImagesInQueue(object sender, DoWorkEventArgs e)
        {
            System.ComponentModel.BackgroundWorker worker;
            worker = (System.ComponentModel.BackgroundWorker)sender;

            for (int i = 0; i < imagesToProcess.Count; i++)
            {
                processImage(imagesToProcess[i]);
                worker.ReportProgress((int)((i * 100) / (imagesToProcess.Count - 1)));
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            testResultXml.saveFile();
            runButton.Enabled = true;
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            int currentImage = ((e.ProgressPercentage / 100) * imagesToProcess.Count);
            textBox4.Text = "" + (int)executionTime.Average() + " ms";
            textBox3.Text = "" + perfectImages;
            textBox5.Text = "" + (int)executionTime.Sum() + " ms";
            textBox2.Text = "" + (int)ocrAccuracy.Average() + " %";
            imagesDoneTextBox.Text = "" + currentImage;
            progressBar1.Value = e.ProgressPercentage;
        }

        private void panel1_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] files = (string[])e.Data.GetData(
                    DataFormats.FileDrop);
                foreach (string file in files)
                {
                    FileInfo fileInfo = new FileInfo(file);
                    if (fileInfo.Extension.ToLower() == ".jpg" || fileInfo.Extension.ToLower() == ".bmp" || fileInfo.Extension.ToLower() == ".png")
                    {
                        imagesToProcess.Add(new TestsetImage(new Bitmap(fileInfo.FullName), fileInfo.Name, new String[1]{"00-00-00"}));
                    }
                }
            }
        }

        private void panel1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Move;
            else
                e.Effect = DragDropEffects.None;
        }
    }
}
